package com.yixing.tech.entity.entity.attr;

import org.apache.commons.lang3.StringUtils;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.base.CustomAggregationOperation;
import com.yixing.tech.common.enums.YesOrNo;
import com.yixing.tech.entity.entity.RequestType;
import com.yixing.tech.common.vo.s5.EntitySchema;
import com.yixing.tech.entity.service.EntityBaseService;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author yixing tech
 * at 2021/10/9
 * describe：
 */
@Component
public final class MultiObject extends AttrType {
    public MultiObject() {
        super("多选对象", "multiObject");
    }

    @Resource
    private EntityBaseService ebs;
    private static MultiObject self;

    @PostConstruct
    private void init() {
        self = this;
    }

    @Override
    public void out(List<AggregationOperation> operations, EntitySchema.AttrVO attr) throws BusinessException {
        super.out(operations, attr);
        String relationalF = attr.getRelationalField();
        String templateId = attr.getReference().toString();
        String objTableName = "entity_" + templateId;
        String addFields = "";
        EntitySchema cond = self.ebs.queryByTableId(templateId);
        String agentCode = cond.getAgentAttrCode();
        if (!StringUtils.isEmpty(agentCode)) {
            addFields = "{$addFields: {name:'$" + agentCode + "'}},";
        }

        String sql = "{ $lookup:{ " +
                "from:'" + objTableName + "'," +
                "let:{ location_id:'$" + attr.getCode() + "'}," +
                "pipeline:[" +
                "{$match:" +
                "{'$and':[" + "{'isDelete':0}," +
                "{$expr:{" +
                "$in:['$" + (ObjectUtils.isEmpty(relationalF) ? "_id" : relationalF) + "',{$ifNull :['$$location_id',[]]}]" +
                "}" +
                "}" +
                "]" +
                "}" +
                "}" +
                addFields +
                "]," +
                "as:'" + attr.getCode() + "'}}";
        operations.add(new CustomAggregationOperation(sql));
    }

    @Override
    public void out(List<AggregationOperation> operations, EntitySchema.AttrVO attr, RequestType requestType) throws BusinessException {
        if (requestType == RequestType.SIMPLE) {
            super.out(operations, attr);
            String relationalF = attr.getRelationalField();
            String templateId = attr.getReference().toString();
            String objTableName = "entity_" + templateId;
            String addFields = "";
            EntitySchema cond = self.ebs.queryByTableId(templateId);
            String agentCode = cond.getAgentAttrCode();
            if (!StringUtils.isEmpty(agentCode)) {
                addFields = "{$addFields: {name:'$" + agentCode + "'}},";
            }

            String sql = "{ $lookup:{ " +
                    "from:'" + objTableName + "'," +
                    "let:{ location_id:'$" + attr.getCode() + "'}," +
                    "pipeline:[" +
                    "{$match:" +
                    "{'$and':[" + "{'isDelete':0}," +
                    "{$expr:{" +
                    "$in:['$" + (ObjectUtils.isEmpty(relationalF) ? "_id" : relationalF) + "',{$ifNull :['$$location_id',[]]}]" +
                    "}" +
                    "}" +
                    "]" +
                    "}" +
                    "}" +
                    addFields +
                    "{$project:{_id:1" + (!StringUtils.isEmpty(agentCode) ? ",name:1}}" : "}}") +
                    "]," +
                    "as:'" + attr.getCode() + "'}}";
            operations.add(new CustomAggregationOperation(sql));
        } else {
            out(operations, attr);
        }
    }

    @Override
    public Object wrapValue(EntitySchema.AttrVO attr, Object value, MongoTemplate mongoTemplate, EntityBaseService objService, String tenantId) throws BusinessException {
        if (ObjectUtils.isEmpty(value)) {
            return value;
        }
        String[] values = value.toString().trim().split(",");
        // 关联的对象编码
        String reference = Optional.ofNullable(attr.getReference()).map(String::valueOf).orElse(null);
        if (StringUtils.isBlank(reference)) {
            throw new BusinessException("缺少关联对象的编码");
        }
        // 查询关联对象信息
        EntitySchema referenceObj = objService.queryByTableId(reference);
        if (referenceObj == null) {
            throw new BusinessException("关联对象的定义不存在");
        }

        // 通过 agentAttrCode 作为key 来查询对象
        String agentAttrCode = referenceObj.getAgentAttrCode();
        if (StringUtils.isBlank(agentAttrCode)) {
            throw new BusinessException("关联对象的agentAttrCode字段为空，请先定义");
        }

        // 查询对象
        List<Document> referenceData = mongoTemplate.find(Query.query(Criteria.where("isDelete").ne(YesOrNo.YES.ordinal())
                .and(agentAttrCode).in(values).and("tenantId").is(tenantId)), Document.class, "entity_" + reference);
        referenceData.forEach(doc -> {
            doc.put("name", doc.get(agentAttrCode));
        });
        return referenceData;
    }
}
